#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h" // 事件组
#include "esp_log.h"

#include "io_button.h"
#include "Base.h"


/*定义按钮和掩码*/
#define BUTTON_SEL_MAKE(pin) (1ULL << (pin))
#define BUTTON_SEL (BUTTON_SEL_MAKE(BUTTON_UP)) | (1ULL << (BUTTON_DOWN)) | (1ULL << (BUTTON_PRESS))
#define ESP_INTR_FLAG_DEFAULT 0 //中断标志位
static char *TAG = "BUTTON";
static void gpio_isr_handler(void* arg);
static QueueHandle_t gpio_evt_queue = NULL; // 消息队列句柄,传递中断消息

int device_button_io_init()
{
    /*配置输出引脚*/
    gpio_config_t io_conf = {};
    io_conf.intr_type = GPIO_INTR_NEGEDGE;        // 下降沿触发
    io_conf.mode = GPIO_MODE_INPUT;               // 输出模式
    io_conf.pin_bit_mask = (BUTTON_SEL);            // 输出位掩码
    io_conf.pull_down_en = 0;                      // 下拉
    io_conf.pull_up_en = 1;                        // 上拉     
    gpio_config(&io_conf);                         // 配置 GPIO

    /*安装中断服务*/
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);                   
    gpio_isr_handler_add(BUTTON_UP,gpio_isr_handler, (void*) BUTTON_UP);        //安装回调
    gpio_isr_handler_add(BUTTON_DOWN,gpio_isr_handler, (void*) BUTTON_DOWN);    //安装回调
    gpio_isr_handler_add(BUTTON_PRESS,gpio_isr_handler, (void*) BUTTON_PRESS);  //安装回调

    /*创建消息队列*/
    gpio_evt_queue = xQueueCreate(1, sizeof(uint32_t));         // 创建队列以处理来自 ISR 的 GPIO 事件
    if (gpio_evt_queue == NULL) {  
        ESP_LOGE(TAG, "Failed to create GPIO event queue");  
    return -1; // 或者其他错误代码  
}
    // xTaskCreate(button_event, "button_event", 4096, self, 10, NULL);   // 开始 gpio task
    ESP_LOGI(TAG,"button is init");
    return 0;
}

/*接收中断消息并发送*/
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;      // 获取中断引脚编号
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); //发送中断消息
}

/*中断后执行的逻辑*/
int device_button_io_get(void)
{
    static uint32_t io_num;
    static bool but_Temp;
    /*接收到了中断消息*/
    if (xQueueReceive(gpio_evt_queue, &io_num, 10/portTICK_PERIOD_MS)) 
    {
        /*防抖方法*/
        int io_num_ = (int)io_num;
        vTaskDelay(10 / portTICK_PERIOD_MS);
        but_Temp = gpio_get_level(io_num);
        if (but_Temp==0)
        {
            printf("button is %d\n",io_num_);
            return io_num;
        }
    }else{
        vTaskDelay(10 / portTICK_PERIOD_MS);
        // printf("button is not press\n");
        return 0;
    }
    return -1;
}